package git.soulbgm.service.impl;

import git.soulbgm.pojo.ClearAlarmInfo;
import git.soulbgm.pojo.ProduceAlarmInfo;
import git.soulbgm.service.AlarmInfoReport;
import git.soulbgm.service.AlarmInfoService;
import git.soulbgm.thread.ClearAlarmInfoThread;
import git.soulbgm.thread.ProduceAlarmInfoThread;
import git.soulbgm.thread.ThreadTool;
import git.soulbgm.utils.IpUtil;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;

import static git.soulbgm.common.MonitorConstants.*;

/**
 * 告警信息上报数据库实现类
 *
 * @author SoulBGM
 * @date 2021/8/22 22:07
 */
@Service
public class AlarmInfoReportDatabaseImpl implements AlarmInfoReport {

    private final AlarmInfoService alarmInfoService;

    public AlarmInfoReportDatabaseImpl(AlarmInfoService alarmInfoService) {
        this.alarmInfoService = alarmInfoService;
        ThreadTool.init(this);
    }

    @Override
    public void nodeUsedThresholdExceededAlarm(Integer nodeCode, String ruleType, String eventCode, String alarmContent, Double value) {
        String alarmObject = MONITOR_AGENT + "_" + nodeCode;
        commonAlarm(ruleType, eventCode, alarmContent, value, alarmObject);
    }

    @Override
    public void nodeUsedThresholdExceededClearAlarm(Integer nodeCode, String ruleType, String eventCode, Double value) {
        String alarmObject = MONITOR_AGENT + "_" + nodeCode;
        commonClearAlarm(ruleType, eventCode, value, alarmObject);
    }

    private void commonClearAlarm(String ruleType, String eventCode, Double value, String alarmObject) {
        ClearAlarmInfo info = setClearAlarmInfo(alarmObject, ruleType, eventCode);
        info.setThreshold(value);
        sendAlarmInfo(info);
    }

    @Override
    public void nodeDiskUsedThresholdExceededAlarm(Integer nodeCode, String ruleType, String eventCode, String dirName, String alarmContent, Double value) {
        String alarmObject = MONITOR_AGENT + "_" + nodeCode + "_" + dirName;
        commonAlarm(ruleType, eventCode, alarmContent, value, alarmObject);
    }

    @Override
    public void nodeDiskUsedThresholdExceededClearAlarm(Integer nodeCode, String ruleType, String eventCode, String dirName, Double value) {
        String alarmObject = MONITOR_AGENT + "_" + nodeCode + "_" + dirName;
        commonClearAlarm(ruleType, eventCode, value, alarmObject);
    }

    @Override
    @Async
    public void nodeRebootAlarm(Integer nodeCode, String alarmContent) {
        String alarmObject = MONITOR_AGENT + "_" + nodeCode;
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, alarmObject, RULE_TYPE_NODE, EVENT_CODE_NODE_REBOOT);
        sendAlarmInfo(info);
    }

    @Override
    @Async
    public void nodeShutdownAlarm(Integer nodeCode, String alarmContent) {
        String alarmObject = MONITOR_AGENT + "_" + nodeCode;
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, alarmObject, RULE_TYPE_NODE, EVENT_CODE_NODE_SHUTDOWN);
        sendAlarmInfo(info);
    }

    @Override
    @Async
    public void nodeStartingClearAlarm(Integer nodeCode) {
        String alarmObject = MONITOR_AGENT + "_" + nodeCode;
        ClearAlarmInfo info = setClearAlarmInfo(alarmObject, RULE_TYPE_NODE, EVENT_CODE_NODE_REBOOT);
        sendAlarmInfo(info);
        info.setEventCode(EVENT_CODE_NODE_SHUTDOWN);
        sendAlarmInfo(info);
    }

    @Override
    public void serviceRebootAlarm(Integer nodeCode, Integer serviceCode, String alarmContent) {
        String alarmObject = "service_" + serviceCode + "_" + nodeCode;
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, alarmObject, RULE_TYPE_SERVICE, EVENT_CODE_SERVICE_REBOOT);
        sendAlarmInfo(info);
    }

    @Override
    public void serviceShutdownAlarm(Integer nodeCode, Integer serviceCode, String alarmContent) {
        String alarmObject = "service_" + serviceCode + "_" + nodeCode;
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, alarmObject, RULE_TYPE_SERVICE, EVENT_CODE_SERVICE_SHUTDOWN);
        sendAlarmInfo(info);
    }

    @Override
    public void serviceStartingClearAlarm(Integer nodeCode, Integer serviceCode) {
        String alarmObject = "service_" + serviceCode + "_" + nodeCode;
        ClearAlarmInfo info = setClearAlarmInfo(alarmObject, RULE_TYPE_SERVICE, EVENT_CODE_SERVICE_REBOOT);
        sendAlarmInfo(info);
        info.setEventCode(EVENT_CODE_SERVICE_SHUTDOWN);
        sendAlarmInfo(info);
    }

    @Override
    public void softwareRebootAlarm(Integer nodeCode, String processName, Integer checkPort, String alarmContent) {
        String alarmObject = "software_" + processName + "_" + checkPort + "_" + nodeCode;
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, alarmObject, RULE_TYPE_SOFTWARE, EVENT_CODE_SOFTWARE_REBOOT);
        sendAlarmInfo(info);
    }

    @Override
    public void softwareShutdownAlarm(Integer nodeCode, String processName, Integer checkPort, String alarmContent) {
        String alarmObject = "software_" + processName + "_" + checkPort + "_" + nodeCode;
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, alarmObject, RULE_TYPE_SOFTWARE, EVENT_CODE_SOFTWARE_SHUTDOWN);
        sendAlarmInfo(info);
    }

    @Override
    public void softwareStartingClearAlarm(Integer nodeCode, String processName, Integer checkPort) {
        String alarmObject = "software_" + processName + "_" + checkPort + "_" + nodeCode;
        ClearAlarmInfo info = setClearAlarmInfo(alarmObject, RULE_TYPE_SOFTWARE, EVENT_CODE_SOFTWARE_REBOOT);
        sendAlarmInfo(info);
        info.setEventCode(EVENT_CODE_SOFTWARE_SHUTDOWN);
        sendAlarmInfo(info);
    }

    @Override
    public void nodeTimeSyncExceptionAlarm(Integer nodeCode, String ruleType, String eventCode, String alarmContent, Double value) {
        String alarmObject = MONITOR_AGENT + "_" + nodeCode;
        commonAlarm(ruleType, eventCode, alarmContent, value, alarmObject);
    }

    @Override
    public void nodeTimeSyncExceptionClearAlarm(Integer nodeCode, String ruleType, String eventCode, Double value) {
        String alarmObject = MONITOR_AGENT + "_" + nodeCode;
        commonClearAlarm(ruleType, eventCode, value, alarmObject);
    }

    @Override
    public void equipmentPingFailureAlarm(String ip, String alarmContent) {
        String alarmObject = "equipment_port_" + ip;
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, alarmObject, RULE_TYPE_CONNECTION, EVENT_CODE_EQUIPMENT_PING_FAILURE);
        sendAlarmInfo(info);
    }

    @Override
    public void equipmentPingSuccessClearAlarm(String ip) {
        String alarmObject = "equipment_port_" + ip;
        ClearAlarmInfo info = setClearAlarmInfo(alarmObject, RULE_TYPE_CONNECTION, EVENT_CODE_EQUIPMENT_PING_FAILURE);
        sendAlarmInfo(info);
    }

    @Override
    public void jobExecuteExceptionAlarm(String alarmContent, String className) {
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, "job-" + className, RULE_TYPE_BUSINESS, EVENT_CODE_NODE_REBOOT);
        sendAlarmInfo(info);
    }

    @Override
    public void threadBlockingAlarm(Integer nodeCode, Integer serviceCode, String poolName, String alarmContent) {
        String alarmObject = "service_" + serviceCode + "_" + nodeCode + "_" + poolName;
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, alarmObject, RULE_TYPE_SERVICE, EVENT_CODE_SERVICE_THREAD_BLOCKING);
        sendAlarmInfo(info);
    }

    /**
     * 通用告警
     *
     * @param ruleType     规则类型
     * @param eventCode    事件编号
     * @param alarmContent 告警内容
     * @param value        检测数值
     * @param alarmObject  告警对象
     */
    private void commonAlarm(String ruleType, String eventCode, String alarmContent, Double value, String alarmObject) {
        ProduceAlarmInfo info = setProduceAlarmInfo(alarmContent, alarmObject, ruleType, eventCode);
        info.setThreshold(value);
        sendAlarmInfo(info);
    }

    /**
     * 设置通用的告警信息
     *
     * @param alarmContent 告警内容
     * @param alarmObject  告警对象
     * @param ruleType     规则类型
     * @param eventCode    事件编号
     * @return {@link ProduceAlarmInfo}
     */
    private ProduceAlarmInfo setProduceAlarmInfo(String alarmContent, String alarmObject, String ruleType, String eventCode) {
        ProduceAlarmInfo info = new ProduceAlarmInfo();
        info.setAlarmContent(alarmContent);
        info.setAlarmObject(alarmObject);
        info.setRuleType(ruleType);
        info.setEventCode(eventCode);
        info.setIp(IpUtil.getLocalHost());
        info.setCreateTime(new Date());
        return info;
    }

    /**
     * 设置通用的告警信息
     *
     * @param alarmObject 告警对象
     * @param ruleType    规则类型
     * @param eventCode   事件编号
     * @return {@link ProduceAlarmInfo}
     */
    private ClearAlarmInfo setClearAlarmInfo(String alarmObject, String ruleType, String eventCode) {
        ClearAlarmInfo info = new ClearAlarmInfo();
        info.setAlarmObject(alarmObject);
        info.setRuleType(ruleType);
        info.setEventCode(eventCode);
        info.setIp(IpUtil.getLocalHost());
        info.setMachineHandleTime(System.currentTimeMillis());
        return info;
    }

    /**
     * 发送报警信息
     *
     * @param info 信息
     */
    private void sendAlarmInfo(Object info) {
        if (info instanceof ProduceAlarmInfo) {
            ThreadTool.IO_INTENSIVE_THREAD_POOL.execute(new ProduceAlarmInfoThread((ProduceAlarmInfo) info, alarmInfoService));
        } else if (info instanceof ClearAlarmInfo) {
            ThreadTool.IO_INTENSIVE_THREAD_POOL.execute(new ClearAlarmInfoThread((ClearAlarmInfo) info, alarmInfoService));
        }
    }

}
